const express = require('express');
const i18n = require('i18n');
const bodyParser = require('body-parser');
const path = require('path');
const chalk = require('chalk'); // https://www.npmjs.com/package/chalk
const utils = require('./utils');
const logger = require('./utils/_logger');
const resextra = require('./utils/_resextra');
const session = require('express-session');
const cookieParser = require('cookie-parser');
const db = require("./models");
const utilsSchedule = require('./utils/_schedule')
const snakecaseKeys = async (data) => (await import('snakecase-keys')).default(data);

// 路由加载
const mount = require('mount-routes');
const app = express();

//访问 .env文件
const dotenv = require('dotenv');
dotenv.config();


// 配置i18n
i18n.configure({
    locales: ['en', 'zh'], // 支持的语言列表
    directory: path.join(__dirname, 'locales'), // 存放语言文件的目录
    defaultLocale: 'zh', // 默认语言
    objectNotation: true, // 支持对象方式的key
    queryParameter: 'lang', // 支持通过查询参数切换语言
    autoReload: true, // 自动重新加载更改的语言文件
    syncFiles: true, // 同步语言文件
    cookie: 'locale', // 设置cookie用于保存语言
});
app.use(i18n.init)

// 托管静态资源
app.use('/static', express.static(__dirname + '/public'));


// session
app.use(session({
    secret: 'pure_serve',
    resave: false,
    saveUninitialized: false,
    cookie: { secure: false } // 在生产环境中应为 true，要求 HTTPS
}));
app.use(cookieParser());

//处理请求参数解析
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: false }));

db.sequelize.sync().then(_=>{
    // 启动定时任务
    utilsSchedule();
})

// 设置跨域和相应数据格式
app.all('/api/*', async function (req, res, next) {
    // 设置语言
    const lang = req.acceptsLanguages(i18n.getLocales()) || i18n.getLocale();
    res.setLocale(lang);
    // 将前端传递的驼峰风格转换为下划线风格
    req.body && (req.body = await snakecaseKeys(req.body, { deep: true }));
    res.header('Access-Control-Allow-Origin', '*');
    res.header('Access-Control-Allow-Headers', 'X-Requested-With, token');
    res.header('Access-Control-Allow-Headers', 'X-Requested-With, Authorization');
    res.header('Content-Type', 'application/json;charset=UTF-8');
    res.header('Access-Control-Allow-Headers', 'Content-Type,Content-Length, Authorization, Accept,X-Requested-With');
    res.header('Access-Control-Allow-Methods', 'PUT,POST,GET,DELETE,OPTIONS');
    if (req.method == 'OPTIONS') res.send(200);
    /*让options请求快速返回*/
    else next();

})

// 使用swagger API 文档
require('./utils/_swagger')(app);
// 日志
app.use(logger.useAccess());

// 统一响应机制
app.use(resextra);

// 设置 passport 验证路径 ('/api/private/' 开头的都需要进行token)
app.use('/api/private/*', utils.permission.tokenAuth);
app.use('/api/private/*', utils.permission.permissionAuth);



//token 有效性中间件
app.use(function (err, req, res, next) {
    if (err.name === 'UnauthorizedError') {
        logger.warnLog(`token验证失败==>${req.method} ${req.baseUrl + req.path} *** 响应：${JSON.stringify({ data: null, code: err.status || 4, message: err.message || 'token错误' })}`);
        res.sendResultAto( null, 4, "请登录" );
    }
})

// 带路径的用法并且可以打印出路有表  true 代表展示路由表在打印台
mount(app, path.join(process.cwd(), '/routes'), false)

// 处理无响应 如果没有路径处理就返回 Not Found
app.use(function (req, res, next) {
    logger.warnLog(`404==>${req.method} ${req.baseUrl + req.path}`)
    res.sendResult({ data: null, code: -1, message: 'Not Found' })
})


process.on('uncaughtException', function (err) {
    logger.errLog(err.stack) // 保存错误的调用栈
})

app.listen(process.env.DEV_PORT, () => {
    console.log(chalk.bold.green(`项目启动成功: ${process.env.DEV_URL}:${process.env.DEV_PORT}`));
    console.log(chalk.bold.green(`接口文档地址: ${process.env.DEV_URL}:${process.env.DEV_PORT}/api-docs`));
})

module.exports = app
